﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
#if !WINDOWS_PHONE

#endif
using DARE.Properties;

namespace DARE
{
    /// <summary>
    /// Singleton.
    /// This is a class used for a mapping of a keyboard.
    /// This can load only one mapping at the time.
    /// The default keyboard mapping is the one of a french keyboard.
    /// To add a mapping, just add the mapping file by using the AddLangFile(...).
    /// To change the keyboard mapping, use the Lang property and set the identifier of the
    /// lang file that you want to load.
    /// </summary>
    /// <example>
    /// To add and set the keymaping for an US keyboard:
    /// <code>
    ///     keyMapper.AddLangFile("en-us", "pathOfTheEN-USMappingFile");
    ///     keyMapper.Lang = "en-us";
    /// </code>
    /// here is an example for the key mapping file:
    /// The format of this file is : XNAKeyValue	lowercaseChar	uppercaseChar	altGrChar   description
    /// Those fields are separated by one unique tabulation.
    /// Only the first line with one value is taken (example, if there are two lines with the XNAKeyValue = 34,
    /// only the first will be taken, the second will be avoided)
    /// 
    /// 65	a	A		The A key.
    /// 107				The add key.
    /// 262144				The ALT modifier key.
    /// 93				The application key (Microsoft Natural Keyboard).
    /// 246				The ATTN key.
    /// 66	b	B		The B key.
    /// 8	BS	BS		The BACKSPACE key.
    /// 67	c	C		The C key.
    /// 3	CANCEL		CANCEL	The CANCEL key.
    /// 20	CAPS		CAPS	The CAPS LOCK key.
    /// 12	CL	CL		The CLEAR key.
    /// 131072	CTRLMOD	CTRLMOD		The CTRL modifier key.
    /// 17	CTRL	CTRL		The CTRL key.
    /// 247	CRSEL	CRSEL		The CRSEL key.
    /// 68	d	D		The D key.
    /// 48	à	0	@	The 0 key.
    /// 49	&	1		The 1 key.
    /// 50	é	2	~	The 2 key.
    /// ...
    /// </example>
    public class CKeyMapper
    {
        private bool m_langFileFound = false;
        private string m_lang = "fr";
        private Dictionary<string, string> m_langFiles;

        /// <summary>
        /// This is the dictionary of the upper case keys for the loaded mapping
        /// </summary>
        public Dictionary<Keys, string> Upkeys { get; set; }

        /// <summary>
        /// This is the dictionary of the lower case keys for the loaded mapping
        /// </summary>
        public Dictionary<Keys, string> Lowkeys { get; set; }

        /// <summary>
        /// This is the dictionary of the alt keys for the loaded mapping
        /// </summary>
        public Dictionary<Keys, string> Altkeys { get; set; }

        /// <summary>
        /// Gets/Sets the identifier of the current mapping.
        /// To change the mapping, juste set its identifier to this property
        /// (the file to the mapping needs to be already added to this mapper).
        /// </summary>
        public string Lang
        {
            get { return m_lang; }
            set { m_lang = value; parseLanguageFile(); }
        }

        private static CKeyMapper instance = null;

        /// <summary>
        /// Gets the instance of the mapper. There can be only one instance of this class.
        /// </summary>
        public static CKeyMapper Instance
        {
            get
            {
                if (instance == null)
                    instance = new CKeyMapper();
                return instance;
            }
        }

        public CKeyMapper AddLangFile(string langIdentifier, string path)
        {
            return AddLangFile(langIdentifier, path, true);
        }

        /// <summary>
        /// Adds a mapping file with its identifier.
        /// </summary>
        /// <param name="langIdentifier">string used as identifier for the mapping ("en-us", "fr-fr",...)</param>
        /// <param name="path">the path of the file containing the mapping (the format of the file has to be the format used by this mapper)</param>
        public CKeyMapper AddLangFile(string langIdentifier, string path, bool overrideLang)
        {
            if (m_langFiles.ContainsKey(langIdentifier) && overrideLang)
                m_langFiles[langIdentifier] = path;
            else
                m_langFiles.Add(langIdentifier, path);
            return this;
        }

        /// <summary>
        /// Gets a XNA Keys object representing the key given in parameters.
        /// </summary>
        /// <param name="key">the string representing the key for the current mapping</param>
        public Keys getKeyFromString(string key)//, bool shift = false, bool altgr = false)
        {
            if (Upkeys.ContainsValue(key))
            {
                foreach (Keys k in Upkeys.Keys)
                    if (Upkeys[k] == key)
                        return k;
            }
            else if (Altkeys.ContainsValue(key))
            {
                foreach (Keys k in Altkeys.Keys)
                    if (Altkeys[k] == key)
                        return k;
            }
            else if (Lowkeys.ContainsValue(key))
            {
                foreach (Keys k in Lowkeys.Keys)
                    if (Lowkeys[k] == key)
                        return k;
            }
            return Keys.None;
        }

        /// <summary>
        /// Gets the string representing the XNA Keys.
        /// with the "en-us" mapping, Keys.D1 + shift => "!"
        /// </summary>
        /// <param name="key">the XNA Keys</param>
        /// <param name="shift">if shift is pressed, set this to true</param>
        /// <param name="altgr">if alt is pressed, set this to true</param>
        public string getKeyValue(Keys key, bool shift, bool altgr)
        {
            if (!m_langFileFound)
                return "";
            if (shift && altgr)
                return "";
            if (shift && Upkeys.ContainsKey(key))
                return Upkeys[key];
            else if (altgr && Altkeys.ContainsKey(key))
                return Altkeys[key];
            else if (!shift && Lowkeys.ContainsKey(key))
                return Lowkeys[key];
            return "";
        }

        private bool parseLanguageFile()
        {
            if (!m_langFileFound)
                return false;
            if (!m_langFiles.ContainsKey(m_lang))
                return false;
            StreamReader sr;
            try
            {            
                sr = new StreamReader(m_langFiles[m_lang], Encoding.UTF8, true, 1);
                m_langFileFound = true;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                m_langFileFound = false;
                return false;
            }
            string[] line;
            while (!sr.EndOfStream)
            {
                line = sr.ReadLine().Split('\t');
                if (line.Length < 4)
                    continue;
                if (!char.IsDigit(line[0][0]))
                    continue;
                int value;
                if (!int.TryParse(line[0], out value))
                    continue;
                if (line[1] != "" && !Lowkeys.ContainsKey((Keys)value))
                    Lowkeys.Add((Keys)value, line[1]);
                if (line[2] != "" && !Upkeys.ContainsKey((Keys)value))
                    Upkeys.Add((Keys)value, line[2]);
                if (line[3] != "" && !Altkeys.ContainsKey((Keys)value))
                    Altkeys.Add((Keys)value, line[3]);
            }

            return true;
        }
    
        /// <summary>
        /// Sets the mapping to the default mapping
        /// </summary>
        public void SetDefaultKeymap()
        {
          //#region default charset
          //  string[] lines = new string[]
          //      {
          //          "65	a	A		The A key.",
          //          "107				The add key.",
          //          "262144				The ALT modifier key.",
          //          "93				The application key (Microsoft Natural Keyboard).",
          //          "246				The ATTN key.",
          //          "66	b	B		The B key.",
          //          "8	BS	BS		The BACKSPACE key.",
          //          "67	c	C		The C key.",
          //          "3	CANCEL		CANCEL	The CANCEL key.",
          //          "20	CAPS		CAPS	The CAPS LOCK key.",
          //          "12	CL	CL		The CLEAR key.",
          //          "131072	CTRLMOD	CTRLMOD		The CTRL modifier key.",
          //          "17	CTRL	CTRL		The CTRL key.",
          //          "247	CRSEL	CRSEL		The CRSEL key.",
          //          "68	d	D		The D key.",
          //          "48	0	0	0	The 0 key.",
          //          "49	1	1   1	The 1 key.",
          //          "50	2	2	2	The 2 key.",
          //          "51	3	3	3	The 3 key.",
          //          "52	4	4	4	The 4 key.",
          //          "53	5	5	5	The 5 key.",
          //          "54	6	6	6	The 6 key.",
          //          "55	7	7	7	The 7 key.",
          //          "56	8	8	8	The 8 key.",
          //          "57	9	9	9	The 9 key.",
          //          "110				The decimal key.",
          //          "46	DEL	DEL		The DEL key.",
          //          "111				The divide key.",
          //          "40				The DOWN ARROW key.",
          //          "69	e	E	€	The E key.",
          //          "35	END	END		The END key.",
          //          "13	ENTER	ENTER		The ENTER key.",
          //          "249				The ERASE EOF key.",
          //          "27	ESC	ESC		The ESC key.",
          //          "43				The EXECUTE key.",
          //          "248				The EXSEL key.",
          //          "70	f	F		The F key.",
          //          "112	F1	F1		The F1 key.",
          //          "121	F10	F10		The F10 key.",
          //          "122	F11	F11		The F11 key.",
          //          "123	F12	F12		The F12 key.",
          //          "124	F13	F13		The F13 key.",
          //          "125	F14	F14		The F14 key.",
          //          "126	F15	F15		The F15 key.",
          //          "127	F16	F16		The F16 key.",
          //          "128	F17	F17		The F17 key.",
          //          "129	F18	F18		The F18 key.",
          //          "130	F19	F19		The F19 key.",
          //          "113	F2	F2		The F2 key.",
          //          "131	F20	F20		The F20 key.",
          //          "132	F21	F21		The F21 key.",
          //          "133	F22	F22		The F22 key.",
          //          "134	F23	F23		The F23 key.",
          //          "135	F24	F24		The F24 key.",
          //          "114	F3	F3		The F3 key.",
          //          "115	F4	F4		The F4 key.",
          //          "116	F5	F5		The F5 key.",
          //          "117	F6	F6		The F6 key.",
          //          "118	F7	F7		The F7 key.",
          //          "119	F8	F8		The F8 key.",
          //          "120	F9	F9		The F9 key.",
          //          "71	g	G		The G key.",
          //          "72	h	H		The H key.",
          //          "47				The HELP key.",
          //          "36	HOME	HOME		The HOME key.",
          //          "73	i	I		The I key.",
          //          "45	INS	INS		The INS key.",
          //          "74	j	J		The J key.",
          //          "75	k	K		The K key.",
          //          "76	l	L		The L key.",
          //          "162	LCTRL	LCTRL		The left CTRL key.",
          //          "37	LEFT	LEFT		The LEFT ARROW key.",
          //          "10				The LINEFEED key.",
          //          "164	LALT	LALT		The left ALT key.",
          //          "160	LSHIFT	LSHIFT		The left SHIFT key.",
          //          "77	m	M		The M key.",
          //          "18	ALT	ALT		The ALT key.",
          //          "106				The multiply key.",
          //          "78	n	N		The N key.",
          //          "34				The PAGE DOWN key.",
          //          "144				The NUM LOCK key.",
          //          "96	0	0		The 0 key on the numeric keypad.",
          //          "97	1	1		The 1 key on the numeric keypad.",
          //          "98	2	2		The 2 key on the numeric keypad.",
          //          "99	3	3		The 3 key on the numeric keypad.",
          //          "100	4	4		The 4 key on the numeric keypad.",
          //          "101	5	5		The 5 key on the numeric keypad.",
          //          "102	6	6		The 6 key on the numeric keypad.",
          //          "103	7	7		The 7 key on the numeric keypad.",
          //          "104	8	8		The 8 key on the numeric keypad.",
          //          "105	9	9		The 9 key on the numeric keypad.",
          //          "79	o	0		The O key.",
          //          "223	!	§		Oem8 OEM specific.",
          //          "226	<	>		OemBackslash The OEM angle bracket or backslash key on the RT 102 key keyboard (Windows 2000 or later).",
          //          "254				The CLEAR 	key.",
          //          "221	^	¨		OemCloseBrackets The OEM close bracket key on a US standard keyboard (Windows 2000 or later).",
          //          "188	,	?		Oemcomma The OEM comma key on any country/region keyboard (Windows 2000 or later).",
          //          "189				OemMinus The OEM minus key on any country/region keyboard (Windows 2000 or later).",
          //          "219	)	°	]	OemOpenBrackets	The OEM open bracket key on a US standard keyboard (Windows 2000 or later).",
          //          "190	;	.		OemPeriod	The OEM period key on any country/region keyboard (Windows 2000 or later).",
          //          "220	*	µ		OemPipe	The OEM pipe key on a US standard keyboard (Windows 2000 or later).",
          //          "187	=	+	}	Oemplus	The OEM plus key on any country/region keyboard (Windows 2000 or later).",
          //          "191	:	/		OemQuestion	The OEM question mark key on a US standard keyboard (Windows 2000 or later).",
          //          "222	²	²		OemQuotes The OEM singled/double quote key on a US standard keyboard (Windows 2000 or later).",
          //          "186	$	£	¤	OemSemicolon The OEM semicolon key on a US standard keyboard (Windows 2000 or later).",
          //          "192				Oemtilde The OEM tilde key on a US standard keyboard (Windows 2000 or later).",
          //          "80	p	P		The P key.",
          //          "253			The PA1 key.",
          //          "34			The PAGE DOWN key.",
          //          "33			The PAGE UP key.",
          //          "19			The PAUSE key.",
          //          "250			The PLAY key.",
          //          "42			The PRINT key.",
          //          "44				The PRINT SCREEN key.",
          //          "33				The PAGE UP key.",
          //          "229				The PROCESS KEY key.",
          //          "81	q	Q		The Q key.",
          //          "82	r	R		The R key.",
          //          "163	RCTRL	RCTRL		The right CTRL key.",
          //          "13	RETURN	RETURN		The RETURN key.",
          //          "39	RIGHT	RIGHT		The RIGHT ARROW key.",
          //          "165	RALT	RALT		The right ALT key.",
          //          "161	RSHIFT	RSHIFT		The right SHIFT key.",
          //          "92	RWIN	RWIN		The right Windows logo key (Microsoft Natural Keyboard).",
          //          "83	s	S		The S key.",
          //          "145				The SCROLL LOCK key.",
          //          "41				The SELECT key.",
          //          "108				The separator key.",
          //          "65536				The SHIFT modifier key.",
          //          "16	SHIFT	SHIFT		The SHIFT key.",
          //          "44				The PRINT SCREEN key.",
          //          "32	 	 		The SPACEBAR key.",
          //          "109				The subtract key.",
          //          "84	t	T		The T key.",
          //          "9	TAB	TAB		The TAB key.",
          //          "85	u	U		The U key.",
          //          "38				The UP 	ARROW key.",
          //          "86	v	V		The V key.",
          //          "87	w	W		The W key.",
          //          "88	x	X		The X key.",
          //          "89	y	Y		The Y key.",
          //          "90	z	Z		The Z key.",
          //          "251				The ZOOM ke."   
          //      };
          //  #endregion
#if WINDOWS
            string[] lines = Encoding.UTF8.GetString(Resources.keys_fr).Split('\n');
            string[] l;
            foreach (string line in lines)
            {
                l = line.Split('\t');
                if (line.Length < 4)
                    continue;
                if (!char.IsDigit(l[0][0]))
                    continue;
                int value;
                if (!int.TryParse(l[0], out value))
                    continue;
                if (l[1] != "" && !Lowkeys.ContainsKey((Keys)value))
                    Lowkeys.Add((Keys)value, l[1]);
                if (l[2] != "" && !Upkeys.ContainsKey((Keys)value))
                    Upkeys.Add((Keys)value, l[2]);
                if (l[3] != "" && !Altkeys.ContainsKey((Keys)value))
                    Altkeys.Add((Keys)value, l[3]);
            }
            m_langFileFound = true;
#endif
        }

        private CKeyMapper()
        {
            Upkeys = new Dictionary<Keys, string>();
            Lowkeys = new Dictionary<Keys, string>();
            Altkeys = new Dictionary<Keys, string>();
            //Chemins à définir dans fichier de conf.
            m_langFiles = new Dictionary<string, string>();
            if (!parseLanguageFile())
                SetDefaultKeymap();
        }
    }
}
